/*
 * Exploder
 * 
 * Tero Pyylampi (218437), Jussi Tuurinkoski (211594)
 *
 * Own implementation of the box2d
 * contact listener, which after impact pays attention
 * to the reaction forces applied to the joints
 * and decides whether to break them or not
 * Only instantiated once from the GameEngine
 * and used during the whole game
 */

#include "GameContactListener.h"
#include "../GameEngine.h"
#include "../layers/LayerGame.h"
#include "../misc/GameTouchHandle.h"
#include "../objects/physicobjects/GamePhysicObjectEngine.h"
#include "../objects/physicobjects/GamePhysicObject.h"
#include "../objects/physicobjects/elements/GameConstructionElement.h"
#include "../objects/physicobjects/bombs/GameBomb.h"

const bool CONTACTLISTENER_ENABLED = true;

// default constructor
GameContactListener::GameContactListener( GameEngine *gameEngine ) 
	: mGameEngine( gameEngine ) {}

// default destructor
GameContactListener::~GameContactListener() {}

// called when the contact begins
void GameContactListener::BeginContact( b2Contact* contact ) {
	// TODO
}

// called after the impact
void GameContactListener::EndContact( b2Contact* contact ) {
	// TODO
}

// called before contact is about to happen, used to skip contacts between moving mines and construction elements
void GameContactListener::PreSolve( b2Contact* contact, const b2Manifold* oldManifold ) {
	if( CONTACTLISTENER_ENABLED ) {
		// get bodies
		b2Body *b1 = contact->GetFixtureA()->GetBody(); 
		b2Body *b2 = contact->GetFixtureB()->GetBody();

		// get physic objects
		GamePhysicObject *object1 = mGameEngine->getPhysicObjectEngine()->findOwnerOfBody( b1 );
		GamePhysicObject *object2 = mGameEngine->getPhysicObjectEngine()->findOwnerOfBody( b2 );

		// precaution ...
		if( object1 == 0 || object2 == 0 ) 
			return;

		// skip if another one is ground
		if( object1->getObjectType() == ELEMENT_GROUND || object2->getObjectType() == ELEMENT_GROUND )
			return;

		// check if another one is already to be removed
		if( object1->canBeRemovedFromTheGame() || object2->canBeRemovedFromTheGame() ) {
			contact->SetEnabled( false );
			return;
		}

		// check if another one of the objects is a mine carried by a player
		if( mGameEngine->getGameLayer()->getTouchHandle()->getCurrentType() == TOUCH_PHYSICS_OBJECT ) {
			b2Body *touchBody = mGameEngine->getGameLayer()->getTouchHandle()->getHitBody();
			if( touchBody == b1 || touchBody == b2 ) {
				contact->SetEnabled( false );
				return;
			}
		}
	}
}

// called after everything has happened, checks whether to break items
void GameContactListener::PostSolve( b2Contact* contact, const b2ContactImpulse* impulse ) {
	if( CONTACTLISTENER_ENABLED ) {
		// get bodies
		b2Body *b1 = contact->GetFixtureA()->GetBody(); 
		b2Body *b2 = contact->GetFixtureB()->GetBody();

		// get physic objects
		GamePhysicObject *object1 = mGameEngine->getPhysicObjectEngine()->findOwnerOfBody( b1 );
		GamePhysicObject *object2 = mGameEngine->getPhysicObjectEngine()->findOwnerOfBody( b2 );

		// find the highest impulse
		float maxImpulse = 0.0f;
		for( int i = 0; i < contact->GetManifold()->pointCount; ++i )
			maxImpulse = b2Max( maxImpulse, impulse->normalImpulses[ i ] );

		// damage objects, prevent continuous collisions with a small treshold
		if( maxImpulse > 20.0f ) {
			object1->takeDamage( maxImpulse, b1 );
			object2->takeDamage( maxImpulse, b2 );
		}
	}
}

